/*
 * Copyrignt (c) xuzeshui.com. All Rights Reserved.
 * Author: Zeshui Xu<i@xuzeshui.com>
 * Created Time: 2015-11-11 19:25:57
 * Last Modified: 2017-07-21 17:59:05
 * File Name: register/register.go
 * Description:
 */
package register

import (
	"time"

	"passport/account"
	"passport/captcha"
	"passport/errorcode"
	"passport/invitecode"
	"passport/models"
	"passport/user"

	"doubimeizhi.com/utility"

	log "github.com/cihub/seelog"
)

var (
	mobileRegisterService *MobileRegisterService
)

/*
	手机注册请求
*/
type MobileRegisterReq struct {
	RegIp      string
	RegPlat    int8
	AKId       int
	Vuid       string
	Mobile     string `json:"mobile"`
	Captcha    string `json:"captcha"`
	InviteCode string `json:"invitation"`
	Password   string `json:"password"`
	NickName   string `json:"nick_name"`
}

/*
	手机注册响应
*/
type MobileRegisterResp struct {
	AccessToken  string
	Userid       string
	ExpireSecond int
	HXAccount    string
	HXPasswd     string
}

/*
	手机一键注册登录请求
*/
type MobileRegLoginReq struct {
	RegIp   string
	RegPlat int8
	AKId    int
	Mobile  string `json:"mobile"`
	Captcha string `json:"captcha"`
	Bid     uint   `json:"bid"`
}

/*
	手机一键注册登录响应
*/
type MobileRegLoginResp struct {
	MobileRegisterResp
}

/*
	MobileRegisterService
*/
type MobileRegisterService struct{}

/*
	通过手机号注册账号
	响应code,msg,resp
	当且仅当code为EC_GL_SUCCESS时候resp才有效
*/
func (p *MobileRegisterService) RegisterAccountForMobile(req *MobileRegisterReq) (uint, string, *MobileRegisterResp) {
	if req.Captcha == "" {
		return errorcode.EC_REGISTER_MOBILE_CAPTCHA_EMPTY, "captcha is empty", nil
	}
	if req.NickName == "" {
		return errorcode.EC_REGISTER_MOBILE_NICKNAME_EMPTY, "nickname is empty", nil
	}
	if req.Password == "" {
		return errorcode.EC_REGISTER_MOBILE_PASSWORD_EMPTY, "password is empty", nil
	}
	//检查验证码是否正确
	validateCaptchaReq := &captcha.ValidateCaptchaReq{
		Mobile:  req.Mobile,
		Captcha: req.Captcha,
		Bid:     captcha.CAPTCHA_MOBILE_REGISTER,
	}
	if code, msg := captcha.GetCaptchaService().ValidateCaptchaForMobile(validateCaptchaReq); code != errorcode.EC_GL_SUCCESS {
		return code, msg, nil
	}

	isSpecialIC := invitecode.GetInviteCodeService().IsSpecialInviteCode(req.InviteCode)
	inviteUserid := ""
	if !isSpecialIC { //非办事处特殊邀请码
		inviteUserid = invitecode.GetInviteCodeService().GetUseridByInviteCode(req.InviteCode) //获取invite_code对应的userid

		//针对填写了邀请码,验证邀请码是否正确
		if req.InviteCode != "" && inviteUserid == "" {
			return errorcode.EC_REGISTER_INVITECODE_WRONG, "注册邀请码不正确", nil
		}
	}

	//手机号是否已注册过
	if ai, err := account.GetAccountService().GetAllAccountInfo(account.ACCOUNT_TYPE_MOBILE, req.Mobile); err != nil {
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	} else if ai != nil {
		return errorcode.EC_REGISTER_MOBILE_REGISTED, "register yet", nil
	}

	dispIC := invitecode.GetInviteCodeService().ObtainNewInviteCode() //分配一个邀请码

	//userid用户信息生成
	userid := utility.GenerateUUIDToken()
	uinfoChanger := user.NewUserInfoChanger(userid)
	uinfoChanger.SetUserid(userid)
	uinfoChanger.SetPassword(req.Password)
	uinfoChanger.SetMobile(req.Mobile)
	uinfoChanger.SetNickName(req.NickName)
	uinfoChanger.SetIsThirdAccount(account.AI_SELF_ACCOUNT) //非第三方账号
	uinfoChanger.SetRegIp(req.RegIp)
	uinfoChanger.SetRegPlat(req.RegPlat)
	uinfoChanger.SetVuid(req.Vuid)
	uinfoChanger.SetInviteBy(req.InviteCode)
	uinfoChanger.SetInsertTime(time.Now().Format("2006-01-02 15:04:05"))
	uinfoChanger.SetInviteCode(dispIC)
	if err := uinfoChanger.Save(); err != nil {
		log.Warnf("uinfoChanger save error, msg: %s", err.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	//手机登陆账号生成
	aichanger := account.NewAccountInfoChanger(req.Mobile, account.ACCOUNT_TYPE_MOBILE)
	aichanger.SetAccount(req.Mobile)
	aichanger.SetAccountType(account.ACCOUNT_TYPE_MOBILE)
	aichanger.SetUserid(userid)
	aichanger.SetActive(account.AI_ACTIVE_ALLOW_LOGIN)
	aichanger.SetThirdAccount(account.AI_SELF_ACCOUNT)
	aichanger.SetBindStatus(account.AI_BIND_STATUS)
	aichanger.SetInsertTime(time.Now().Format("2006-01-02 15:04:05"))
	if err := aichanger.Save(); err != nil {
		log.Errorf("aichanger save error, msg: %s", err.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	//成功获取到邀请码
	if dispIC != "" {
		invitecode.GetInviteCodeService().CreateICAccount(userid, dispIC)
	}

	//成功通过邀请码注册,要纪录是谁邀请的
	if !isSpecialIC && inviteUserid != "" {
		invitecode.GetInviteCodeService().RegSuccFromInviteCode(inviteUserid, userid)
	}

	//手机账号绑定
	account.GetAccountBindService().RecordUserAccountBind(userid, account.ACCOUNT_TYPE_MOBILE, req.Mobile)

	//access_token生成
	accessToken, ok := account.GetAccessTokenService().GenerateAndRecordAccessToken(userid, req.AKId)
	if !ok {
		log.Errorf("GenerateAndRecordAccessToken failed")
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	//让验证码失效
	captcha.GetCaptchaService().DeleteCaptchaInfoItem(req.Mobile, captcha.CAPTCHA_MOBILE_REGISTER)

	resp := &MobileRegisterResp{
		AccessToken:  accessToken,
		Userid:       userid,
		ExpireSecond: models.GetAccessTokenExpireSecond(),
	}
	return errorcode.EC_GL_SUCCESS, errorcode.Msg(errorcode.EC_GL_SUCCESS), resp
}

/*
	通过手机号一键注册登录
*/
func (p *MobileRegisterService) RegLogin(req *MobileRegLoginReq) (uint, string, *MobileRegLoginResp) {
	if req.Captcha == "" {
		return errorcode.EC_REGISTER_MOBILE_CAPTCHA_EMPTY, "captcha is empty", nil
	}
	//检查验证码是否正确
	validateCaptchaReq := &captcha.ValidateCaptchaReq{
		Mobile:  req.Mobile,
		Captcha: req.Captcha,
		Bid:     req.Bid,
	}
	if code, msg := captcha.GetCaptchaService().ValidateCaptchaForMobile(validateCaptchaReq); code != errorcode.EC_GL_SUCCESS {
		return code, msg, nil
	}

	//手机号是否已注册过
	if ai, err := account.GetAccountService().GetAllAccountInfo(account.ACCOUNT_TYPE_MOBILE, req.Mobile); err != nil {
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	} else if ai != nil {
		return p.captchaMobileLogin(ai.Userid, req)
	} else {
		return p.registerMobileAction(req)
	}

}

/*
	手机一键注册新用户
*/
func (p *MobileRegisterService) registerMobileAction(req *MobileRegLoginReq) (uint, string, *MobileRegLoginResp) {
	dispIC := invitecode.GetInviteCodeService().ObtainNewInviteCode() //分配一个邀请码

	//userid用户信息生成
	userid := utility.GenerateUUIDToken()
	uinfoChanger := user.NewUserInfoChanger(userid)
	uinfoChanger.SetUserid(userid)
	uinfoChanger.SetPassword(req.Mobile[5:]) //初始密码手机号后6位
	uinfoChanger.SetMobile(req.Mobile)
	uinfoChanger.SetIsThirdAccount(account.AI_SELF_ACCOUNT) //非第三方账号
	uinfoChanger.SetRegIp(req.RegIp)
	uinfoChanger.SetRegPlat(req.RegPlat)
	uinfoChanger.SetInsertTime(time.Now().Format("2006-01-02 15:04:05"))
	uinfoChanger.SetInviteCode(dispIC)
	if err := uinfoChanger.Save(); err != nil {
		log.Warnf("uinfoChanger save error, msg: %s", err.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	//手机登陆账号生成
	aichanger := account.NewAccountInfoChanger(req.Mobile, account.ACCOUNT_TYPE_MOBILE)
	aichanger.SetAccount(req.Mobile)
	aichanger.SetAccountType(account.ACCOUNT_TYPE_MOBILE)
	aichanger.SetUserid(userid)
	aichanger.SetActive(account.AI_ACTIVE_ALLOW_LOGIN)
	aichanger.SetThirdAccount(account.AI_SELF_ACCOUNT)
	aichanger.SetBindStatus(account.AI_BIND_STATUS)
	aichanger.SetInsertTime(time.Now().Format("2006-01-02 15:04:05"))
	if err := aichanger.Save(); err != nil {
		log.Errorf("aichanger save error, msg: %s", err.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	//成功获取到邀请码
	if dispIC != "" {
		invitecode.GetInviteCodeService().CreateICAccount(userid, dispIC)
	}

	//手机账号绑定
	account.GetAccountBindService().RecordUserAccountBind(userid, account.ACCOUNT_TYPE_MOBILE, req.Mobile)

	//access_token生成
	accessToken, ok := account.GetAccessTokenService().GenerateAndRecordAccessToken(userid, req.AKId)
	if !ok {
		log.Errorf("GenerateAndRecordAccessToken failed")
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	//让验证码失效
	captcha.GetCaptchaService().DeleteCaptchaInfoItem(req.Mobile, req.Bid)

	resp := &MobileRegLoginResp{}
	resp.AccessToken = accessToken
	resp.Userid = userid
	resp.ExpireSecond = models.GetAccessTokenExpireSecond()
	return errorcode.EC_GL_SUCCESS, errorcode.Msg(errorcode.EC_GL_SUCCESS), resp
}

/*
	老用户一键登录
*/
func (p *MobileRegisterService) captchaMobileLogin(userid string, req *MobileRegLoginReq) (uint, string, *MobileRegLoginResp) {
	accessToken, ok := account.GetAccessTokenService().GenerateAndRecordAccessToken(userid, req.AKId)
	if !ok {
		log.Errorf("GenerateAndRecordAccessToken error for userid: %s", userid)
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}
	log.Infof("login mobile(captcha) success, mobile: %s with accessToekn: %s, userid: %s", req.Mobile, accessToken, userid)
	resp := &MobileRegLoginResp{}
	resp.AccessToken = accessToken
	resp.Userid = userid
	resp.ExpireSecond = models.GetAccessTokenExpireSecond()
	return errorcode.EC_GL_SUCCESS, errorcode.Msg(errorcode.EC_GL_SUCCESS), resp

}

/*
	获取MobileRegisterService处理对象
*/
func GetMobileRegisterService() *MobileRegisterService {
	return mobileRegisterService
}

func init() {
	mobileRegisterService = &MobileRegisterService{}
}

//web端进行账号的注册行为，去掉短信验证码的发送和验证逻辑, 去掉邀请码验证
func (p *MobileRegisterService) RegisterAccountForMobileByWeb(req *MobileRegisterReq) (uint, string, *MobileRegisterResp) {
	if req.NickName == "" {
		return errorcode.EC_REGISTER_MOBILE_NICKNAME_EMPTY, "nickname is empty", nil
	}
	if req.Password == "" {
		return errorcode.EC_REGISTER_MOBILE_PASSWORD_EMPTY, "password is empty", nil
	}

	//手机号是否已注册过
	if ai, err := account.GetAccountService().GetAllAccountInfo(account.ACCOUNT_TYPE_MOBILE, req.Mobile); err != nil {
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	} else if ai != nil {
		return errorcode.EC_REGISTER_MOBILE_REGISTED, "register yet", nil
	}

	dispIC := invitecode.GetInviteCodeService().ObtainNewInviteCode() //分配一个邀请码

	//userid用户信息生成
	userid := utility.GenerateUUIDToken()
	uinfoChanger := user.NewUserInfoChanger(userid)
	uinfoChanger.SetUserid(userid)
	uinfoChanger.SetPassword(req.Password)
	uinfoChanger.SetMobile(req.Mobile)
	uinfoChanger.SetNickName(req.NickName)
	uinfoChanger.SetIsThirdAccount(account.AI_SELF_ACCOUNT) //非第三方账号
	uinfoChanger.SetRegIp(req.RegIp)
	uinfoChanger.SetRegPlat(req.RegPlat)
	uinfoChanger.SetVuid(req.Vuid)
	uinfoChanger.SetInviteBy(req.InviteCode)
	uinfoChanger.SetInsertTime(time.Now().Format("2006-01-02 15:04:05"))
	uinfoChanger.SetInviteCode(dispIC)
	if err := uinfoChanger.Save(); err != nil {
		log.Warnf("uinfoChanger save error, msg: %s", err.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	//手机登陆账号生成
	aichanger := account.NewAccountInfoChanger(req.Mobile, account.ACCOUNT_TYPE_MOBILE)
	aichanger.SetAccount(req.Mobile)
	aichanger.SetAccountType(account.ACCOUNT_TYPE_MOBILE)
	aichanger.SetUserid(userid)
	aichanger.SetActive(account.AI_ACTIVE_ALLOW_LOGIN)
	aichanger.SetThirdAccount(account.AI_SELF_ACCOUNT)
	aichanger.SetBindStatus(account.AI_BIND_STATUS)
	aichanger.SetInsertTime(time.Now().Format("2006-01-02 15:04:05"))
	if err := aichanger.Save(); err != nil {
		log.Errorf("aichanger save error, msg: %s", err.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	//成功获取到邀请码
	if dispIC != "" {
		invitecode.GetInviteCodeService().CreateICAccount(userid, dispIC)
	}

	//手机账号绑定
	account.GetAccountBindService().RecordUserAccountBind(userid, account.ACCOUNT_TYPE_MOBILE, req.Mobile)

	//access_token生成
	accessToken, ok := account.GetAccessTokenService().GenerateAndRecordAccessToken(userid, req.AKId)
	if !ok {
		log.Errorf("GenerateAndRecordAccessToken failed")
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	}

	resp := &MobileRegisterResp{
		AccessToken:  accessToken,
		Userid:       userid,
		ExpireSecond: models.GetAccessTokenExpireSecond(),
	}
	return errorcode.EC_GL_SUCCESS, errorcode.Msg(errorcode.EC_GL_SUCCESS), resp
}

/*
	通过手机号一键注册登录
*/
func (p *MobileRegisterService) RegLoginByWeb(req *MobileRegLoginReq) (uint, string, *MobileRegLoginResp) {
	//手机号是否已注册过
	if ai, err := account.GetAccountService().GetAllAccountInfo(account.ACCOUNT_TYPE_MOBILE, req.Mobile); err != nil {
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), nil
	} else if ai != nil {
		return p.captchaMobileLogin(ai.Userid, req)
	} else {
		return p.registerMobileAction(req)
	}

}
